#ifndef QECDHMGR_H
#define QECDHMGR_H

#include <QString>
#include <QByteArray>
#include <QDebug>
#include <QScopedPointer>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/core_names.h>
#include <openssl/param_build.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/param_build.h>
#include <openssl/bn.h>


class QECDHMgr
{
public:
    QECDHMgr();

    // 获取最后一次错误信息
    QString GetLastError();

    // 设置CurveName，可以为secp384r1等
    // 系统不支持的加密方式返回false
    bool SetCurveName(QString curveName);

    // 获取CurevName
    QString GetCurveName();

    // 生成密钥对（包含公钥和私钥）
    bool GenerateKeys();

    // 获取私钥
    QString GetPrivateKey(); // for debug

    // 获取公钥
    QString GetPublicKey();

    // 设置私钥
    bool SetPrivateKey(QString hexPrivateKey);

    // 设置公钥
    bool SetPublicKey(QString hexPublicKey);

    // 设置公钥、私钥对
    bool SetKeyPair(QString hexPublicKey, QString hexPrivateKey);

    // 生成对称密钥
    QString DeriveSharedSecret(QString hexPeerPublicKey);

private:

    static int GetHexValue(unsigned char hexDigit)
    {
      static constexpr char hexValues[256] = {
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
        -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      };
      return hexValues[hexDigit];
    }

    // this struct calls "OSSL_PARAM_BLD_free" to delete the pointer
    struct ScopedPointerParamBldDeleter
    {
        static inline void cleanup(OSSL_PARAM_BLD *pointer)
        {
            OSSL_PARAM_BLD_free(pointer);
        }
    };

    // this struct calls "OSSL_PARAM_BLD_free" to delete the pointer
    struct ScopedPointerParamDeleter
    {
        static inline void cleanup(OSSL_PARAM *pointer)
        {
            OSSL_PARAM_free(pointer);
        }
    };

    // this struct calls "OSSL_PARAM_BLD_free" to delete the pointer
    struct ScopedPointerKeyCtxDeleter
    {
        static inline void cleanup(EVP_PKEY_CTX *pointer)
        {
            EVP_PKEY_CTX_free(pointer);
        }
    };

    // this struct calls "OSSL_PARAM_BLD_free" to delete the pointer
    struct ScopedPointerKeyDeleter
    {
        static inline void cleanup(EVP_PKEY *pointer)
        {
            EVP_PKEY_free(pointer);
        }
    };

    // Converts a hex string to BIGNUM.
    BIGNUM* ConvertHexToBigNum(QString hexBigNum);

    // Converts BIGNUM to a hex string.
    // Returns an empty string if convertion fails.
    QString ConvertBigNumToHex(const BIGNUM* bigNum);

    // Converts binary data to a hex string.
    QString ConvertDataToHex(QByteArray data);

    // Converts a hex string to binary data.
    QByteArray ConvertHexToData(QString hex);

    // Create a Peer public key
    bool CreatePeerPublicKey(QString hexPeerPublicKey, QScopedPointer <EVP_PKEY , ScopedPointerKeyDeleter>*  peerPublicKey);

    // Create a Peer private key
    bool CreatePeerPrivateKey(QString hexPeerPrivateKey, QScopedPointer <EVP_PKEY , ScopedPointerKeyDeleter>*  peerPrivateKey);

    // Create a Peer key pair
    bool CreatePeerKeyPair(QString hexPeerPublicKey, QString hexPeerPrivateKey, QScopedPointer <EVP_PKEY , ScopedPointerKeyDeleter>*  peerPrivateKey);


private:

    QScopedPointer <EVP_PKEY , ScopedPointerKeyDeleter> keyPair_;

    QString curveName_;
};

#endif // QECDHMGR_H
